﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Linq.Expressions;
using System.Web.Mvc;
using System.Web.Mvc.Html;
using System.Web.Routing;

using Lilium.Collections;
using Lilium.Web.Mvc.State;
using Lilium.Web.Mvc.Validation;
using Lilium.Web.Mvc.Metadata;
using System.IO;

namespace Lilium.Web.Mvc.Html
{
    public static class ActionLinkExtensions
    {
        public static MvcHtmlString ActionLink<TController>(this HtmlHelper html, string linkText, Expression<Func<TController, ActionResult>> action)
        {
            return ActionLinkExtensions.ActionLink<TController>(html, linkText, action, (object)null);
        }

        public static MvcHtmlString ActionLink<TController>(
            this HtmlHelper html, 
            string linkText, 
            Expression<Func<TController, ActionResult>> action, 
            IDictionary<string, object> routeValues, 
            IDictionary<string, object> htmlAttributes)
        //			where TController: 
        {
            if (html == null) throw new ArgumentNullException("html");

            var combinedRouteValues = html.ViewContext.Controller.GetCombinedRouteValuesWithState(action, routeValues);

            return ActionLinkExtensions.ActionLink(html, linkText, combinedRouteValues, htmlAttributes);
        }

        /// <summary>
        /// Creates action link and encodes specified 
        /// </summary>
        /// <typeparam name="TController"></typeparam>
        /// <param name="html"></param>
        /// <param name="linkText"></param>
        /// <param name="action"></param>
        /// <param name="state"></param>
        /// <returns></returns>
        public static MvcHtmlString ActionLink<TController>(this HtmlHelper html, string linkText, Expression<Func<TController, ActionResult>> action, params Tuple<Type, object>[] state)
        {
            if (html == null) throw new ArgumentNullException("html");
            if (state == null) throw new ArgumentNullException("state");

            var stateService = html.GetService<IStateService>(true);

            var routeValues = state.Select(fs =>
            {
                var filter = (IStatefulObject)html.GetService(fs.Item1, true);
                return stateService.SerializeState(filter, fs.Item2);
            }).ToDictionary(p => p.Key, p => p.Value);

            return ActionLink<TController>(html, linkText, action, routeValues, (IDictionary<string, object>)null);
        }

        public static MvcHtmlString ActionLink<TController>(
            this HtmlHelper htmlHelper,
            string linkText,
            Expression<Func<TController, ActionResult>> action,
            object enabledAttributes,
            object disabledAttributes)
        {
            return ActionLink<TController>(htmlHelper, linkText, action, enabledAttributes, disabledAttributes, null);
        }


        public static MvcHtmlString ActionLink(
            this HtmlHelper html, 
            string linkText, 
            IDictionary<string, object> routeValues, 
            IDictionary<string, object> htmlAttributes)
        {
            if (html == null) throw new ArgumentNullException("html");

            if (!string.IsNullOrEmpty(linkText))
            {
                var stateService = html.GetService<IStateService>(false);

                if (stateService != null)
                {
                    var routeValuesDictionary = new RouteValueDictionary();
                    stateService.SaveObjectsState(routeValuesDictionary);
                    routeValuesDictionary.Merge(routeValues);
                    return System.Web.Mvc.Html.LinkExtensions.RouteLink(html, linkText, routeValuesDictionary, htmlAttributes);
                }
                else
                    return System.Web.Mvc.Html.LinkExtensions.RouteLink(html, linkText, new RouteValueDictionary(routeValues), htmlAttributes);
            }
            else
                return MvcHtmlString.Empty;
        }

        public static MvcHtmlString ActionLink<TController>(this HtmlHelper htmlHelper, string linkText, Expression<Func<TController, ActionResult>> action, object htmlAttributes)
        {
            return ActionLink<TController>(htmlHelper, linkText, action, (IDictionary<string, object>)null, new RouteValueDictionary(htmlAttributes));
        }

        public static MvcHtmlString ActionLink<TController>(this HtmlHelper htmlHelper, string linkText, Expression<Func<TController, ActionResult>> action,
            string confirmMessage)
        {
            return ActionLink(htmlHelper, linkText, action, new { onclick = "javascript:return confirm('" + JavaScriptString.QuoteString(confirmMessage) + "')" });
        }

        public static MvcHtmlString ActionLink<TController>(
            this HtmlHelper html,
            string linkText,
            Expression<Func<TController, ActionResult>> action,
            object enabledAttributes,
            object disabledAttributes,
            string confirmMessage)
        {
            if (html == null) throw new ArgumentNullException("htmlHelper");

            var metadataService = html.GetService<IMetadataService>(true);
            var routeValues = metadataService.GetActionRouteValues(action);
            var stateService = html.GetService<IStateService>(false);
            if (stateService != null)
                stateService.SaveObjectsState(routeValues);

            /* пока убрано
            var validateActionContext = new ValidateActionContext(html.ViewContext.Controller.GetServiceProvider(), routeValues);
            foreach (var validator in redirectData.ActionValidators)
            {
                validator.Validate(validateActionContext);
            }
            if (!validateActionContext.ModelErrors.HasErrors)
            {
            */
            var attributes = new RouteValueDictionary(enabledAttributes);
            if (!string.IsNullOrEmpty(confirmMessage))
                attributes["onclick"] = "javascript:return confirm('" + JavaScriptString.QuoteString(confirmMessage) + "')";
            return html.RouteLink(linkText, routeValues);
            /*
            }
            else
            {
                var tagBuilder = new TagBuilder("div");
                tagBuilder.InnerHtml = html.Encode(linkText);
                tagBuilder.Attributes["title"] = validateActionContext.ModelErrors.GetCombinedMessage();
                tagBuilder.MergeAttributes(new RouteValueDictionary(disabledAttributes));
                return MvcHtmlString.Create(tagBuilder.ToString());
            }
             */
        }

        public static TagWriter BeginActionLink<TController>(this HtmlHelper html, Expression<Func<TController, ActionResult>> action, object htmlAttributes = null)
        {
            if (html == null) throw new ArgumentNullException("html");

            var combinedRouteValues = html.ViewContext.Controller.GetCombinedRouteValuesWithState(action, null);

            var url = UrlHelper.GenerateUrl(null, null, null, combinedRouteValues, html.RouteCollection, html.ViewContext.RequestContext, true);

            TagBuilder builder = new TagBuilder("a");
            builder.MergeAttribute("href", url);

            if (htmlAttributes != null)
                builder.MergeAttributes(htmlAttributes.ToDictionaty());

            return new TagWriter(html.ViewContext, builder);
        }
    }
}